home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d2 / nansi286.arc / NANSI_F.ASM < prev    next >
Assembly Source File  |  1987-07-19  |  17KB  |  637 lines

  1. ;----- nansi_f.asm ---------------------------------------------
  2. ; The ANSI control subroutines.
  3. ; (C) 1986 Daniel Kegel, Pasadena, CA
  4. ; May be distributed for educational and personal use only
  5. ; Each routine is called with the following register usage:
  6. ;  AX = max(1, value of first parameter)
  7. ;  Z flag is set if first parameter is zero.
  8. ;  CX = number of paramters
  9. ;  SI = offset of second parameter from CS
  10. ;  DS = CS
  11. ;  ES:DI points to the current location on the memory-mapped screen.
  12. ;  DX is number of characters remaining on the current screen line.
  13. ; The control routine is free to trash AX, BX, CX, SI, and DS.
  14. ; It must preserve ES, and can alter DX and DI if it wants to move the
  15. ; cursor.
  16. ;
  17. ; Revisions:
  18. ;  19 Aug 85: Fixed horrible bug in insert/delete line.
  19. ;  26 Aug 85: Fixed simple limit-to-one-too-few-lines bug in ins/del line;
  20. ;  anyway, it inserts 24 lines when on line 2 now.  Whether it's fixed...
  21. ;  4 Sept 85: Fixed bug created on 26 Aug 85; when limiting ins/del line
  22. ;  count, we are clearing, not scrolling; fixed BIOS call to reflect this.
  23. ;  30 Jan 86: Added EGA cursor patch
  24. ;  31 Jan 86: Disabled insert/delete char in graphics modes
  25. ;          Implemented keyboard redefinition reset
  26. ;  1 Feb 86: added video_mode and max_x test after mode set
  27. ;----------------------------------------------------------------
  28.  
  29.     include nansi_d.asm
  30.  
  31.     ; To nansi_p.asm
  32.     public    ansi_fn_table
  33.  
  34.     ; From nansi.asm
  35.     extrn    port_6845:word
  36.     extrn    cur_coords:word, saved_coords:word
  37.     extrn    cur_x:byte, max_x:byte
  38.     extrn    cur_y:byte, max_y:byte
  39.     extrn    cur_attrib:byte, wrap_flag:byte
  40.     extrn    xy_to_regs:near
  41.     extrn    get_blank_attrib:near
  42.     extrn    xlate_tab_ptr:word
  43.     extrn    cpr_esc:byte, cprseq:word
  44.     extrn    video_mode:byte
  45.     extrn    lookup:near
  46.     extrn    in_g_mode:near
  47.  
  48.     ; from nansi_p.asm
  49.     extrn    param_buffer:word    ; used in keyboard programming
  50.     extrn    param_end:word
  51.     extrn    redef_end:word
  52.  
  53. keybuf    struc                ; used in making cpr sequence
  54. len    dw    ?
  55. adr    dw    ?
  56. keybuf    ends
  57.  
  58.  
  59. ABS40    segment at 40h
  60.     org    1ah
  61. buffer_head    dw    ?    ; Used in 'flush input buffer' dos call.
  62. buffer_tail    dw    ?
  63.  
  64.     org    49h
  65. crt_mode    db    ?
  66. crt_cols    dw    ?
  67. crt_len        dw    ?
  68. crt_start    dw    ?
  69. cursor_posn    dw    8 dup (?)
  70. cursor_mode    dw    ?
  71. active_page    db    ?
  72. addr_6845    dw    ?
  73. crt_mode_set    db    ?
  74. crt_palette    db    ?
  75.  
  76. ABS40    ends
  77.  
  78. code    segment byte public 'CODE'
  79.     assume cs:code, ds:code
  80.  
  81. ;----- byteout ---------------------------------------------------
  82. ; Converts al to a decimal ASCII string (in 0..99),
  83. ; stores it at ES:DI++.  Returns DI pointing at byte after last digit.
  84. ; Destroys DL.
  85.  
  86. byteout proc    near
  87.     aam
  88.     add    ax, 3030h
  89.     xchg    ah, al
  90.     stosb
  91.     xchg    ah, al
  92.     stosb
  93.     ret
  94. byteout endp
  95.  
  96. ;----- ansi_fn_table -----------------------------------
  97. ; Table of offsets of terminal control subroutines in order of
  98. ; the character that invokes them, @..Z, a..z.    Exactly 53 entries.
  99. ; All the subroutines are defined below in this module.
  100. ansi_fn_table    label    word
  101.     dw    ic,  cup, cdn, cfw, cbk        ; @, A, B, C, D
  102.     dw    nul, nul, nul, hvp, nul        ; E, F, G, H, I
  103.     dw    eid, eil, il,  d_l, nul        ; J, K, L, M, N
  104.     dw    nul, dc,  nul, nul, nul        ; O, P, Q, R, S
  105.     dw    nul, nul, nul, nul, nul        ; T, U, V, W, X
  106.     dw    nul, nul            ; Y, Z
  107.     dw    nul, nul, nul, nul, nul        ; a, b, c, d, e
  108.     dw    hvp, nul, sm,  nul, nul        ; f, g, h, i, j
  109.     dw    nul, rm,  sgr, dsr, nul        ; k, l, m, n, o
  110.     dw    key, nul, nul, scp, nul        ; p, q, r, s, t
  111.     dw    rcp, nul, nul, nul, xoc        ; u, v, w, x, y
  112.     dw    nul                ; z
  113.  
  114. ansi_functions    proc    near        ; set return type to NEAR
  115.  
  116. ;----- nul ---------------------------------------------
  117. ; No-action ansi sequence; called when unknown command given.
  118. nul:    ret
  119.  
  120. ;----- Cursor Motion -----------------------------------------------
  121.  
  122. ;-- cursor to y,x
  123. hvp:    or    al, al        ; First parameter is desired Y coordinate.
  124.     jz    hvp_yok
  125.     dec    ax        ; Convert to zero-based coordinates.
  126. hvp_yok:mov    cur_y, al
  127.     ; Get second parameter, if it is there, and set X with it.
  128.     xor    ax, ax
  129.     cmp    cx, 2        ; was there a second parameter?
  130.     jb    hvp_xok
  131.     lodsb            ; yes.
  132.     or    al, al
  133.     jz    hvp_xok
  134.     dec    ax        ; convert to zero-based coordinates.
  135. hvp_xok:mov    cur_x, al
  136.  
  137.     ; Clip to maximum coordinates.
  138. hvp_set:
  139.     mov    ax, cur_coords        ; al = x, ah = y
  140.     cmp    al, max_x
  141.     jbe    hvp_sxok
  142.         mov    al, max_x
  143.         mov    cur_x, al
  144. hvp_sxok:
  145.     cmp    ah, max_y
  146.     jbe    hvp_syok
  147.         mov    al, max_y
  148.         mov    cur_y, al
  149. hvp_syok:
  150.     ; Set values of DX and DI accordingly.
  151.     call    xy_to_regs
  152.     ret
  153.  
  154. ;-- cursor forward --
  155. cfw:    add    cur_x, al
  156.     jmp    hvp_set
  157.  
  158. ;-- cursor back -----
  159. cbk:    sub    cur_x, al
  160.     jae    cbk_ok
  161.         mov    cur_x, 0
  162. cbk_ok: jmp    hvp_set
  163.  
  164. ;-- cursor down -----
  165. cdn:    add    cur_y, al
  166.     jmp    hvp_set
  167.  
  168. ;-- cursor up -------
  169. cup:    sub    cur_y, al
  170.     jae    cup_ok
  171.         mov    cur_y, 0
  172. cup_ok: jmp    hvp_set
  173.  
  174. ;-- save cursor position --------------------------------------
  175. scp:    mov    ax, cur_coords
  176.     mov    saved_coords, ax
  177.     ret
  178.  
  179. ;-- restore cursor position -----------------------------------
  180. rcp:    mov    ax, saved_coords
  181.     mov    cur_coords, ax
  182.     jmp    hvp_set        ; Clip in case we have switched video modes.
  183.  
  184. ;-- set graphics rendition ------------------------------------
  185. ; Modifies the color in which new characters are written.
  186.  
  187. sgr:    dec    si        ; get back pointer to first parameter
  188.     or    cx, cx        ; Did he give any parameters?
  189.     jnz    sgr_loop
  190.         mov    byte ptr [si], 0    ; no parameters, so fake
  191.         inc    cx            ; one with the default value.
  192.     ; For each parameter
  193. sgr_loop:
  194.         lodsb                ; al = next parameter
  195.         ; Search color table
  196.         push    cx
  197.         mov    cx, colors
  198.         mov    bx, offset color_table-3
  199. sgr_search:
  200.             add    bx, 3
  201.             cmp    al, byte ptr [bx]
  202.             loopnz    sgr_search    ; until match found or done
  203.         jnz    sgr_loopx
  204.  
  205.         ; If parameter named a known color, set the current
  206.         ; color variable.
  207.         mov    ax, [bx+1]
  208.         and    cur_attrib, al
  209.         or    cur_attrib, ah
  210. sgr_loopx:
  211.         pop    cx
  212.         loop    sgr_loop        ; until no more parameters.
  213.     ret
  214.  
  215. ;-- erase in line ----------------------------------------
  216. ; Uses BIOS to scroll away a one-line rectangle
  217. eil:    push    dx
  218.     mov    cx, cur_coords
  219.     mov    dh, ch
  220.     jmp    short scrollem
  221.  
  222. ;-- erase in display -------------------------------------
  223. ; Uses BIOS to scroll away all of display
  224. eid:    cmp    al, 2
  225.     jnz    eid_ignore    ; param must be two
  226.     if    cls_homes_too
  227.         mov    cur_coords, 0
  228.         call    xy_to_regs
  229.     endif
  230.     push    dx
  231.     xor    cx, cx
  232.     mov    dh, max_y
  233. scrollem:
  234.     call    get_blank_attrib
  235.     mov    bh, ah
  236.     mov    dl, max_x
  237.     mov    ax, 600h
  238.     int    10h
  239.     pop    dx
  240. eid_ignore:
  241.     ret
  242.  
  243. ;-- device status report --------------------------------
  244. ; Stuffs an escape, a left bracket, current Y, semicolon, current X,
  245. ; a capital R, and a carriage return into input stream.
  246. ; The coordinates are 1 to 3 decimal digits each.
  247.  
  248. dsr:    push    di
  249.     push    dx
  250.     push    es
  251.     mov    ax, cs
  252.     mov    es, ax
  253.     std            ; Store string in reversed order for fun
  254.     mov    di, offset cpr_esc - 2
  255.     mov    al, cur_y
  256.     inc    al        ; convert to one-based coords
  257.     call    byteout        ; row
  258.     mov    al, ';'        ; ;
  259.     stosb
  260.     mov    al, cur_x
  261.     inc    al        ; convert to one-based coords
  262.     call    byteout        ; column
  263.     mov    al, 'R'        ; R ANSI function 'Cursor Position Report'
  264.     stosb
  265.     mov    al, 13
  266.     mov    word ptr cprseq.adr, di ; save pointer to last char in string
  267.     stosb                ; send a carriage return, too
  268.     mov    ax, offset cpr_esc
  269.     sub    ax, di            ; ax is # of characters in string
  270.     mov    word ptr cprseq.len, ax ; pass info to the getchar routine
  271.     cld
  272.     pop    es
  273.     pop    dx
  274.     pop    di
  275.     ret
  276.  
  277. ;-- keyboard reassignment -------------------------------
  278. ; Key reassignment buffer is between param_end and redef_end+2, exclusive.
  279. ; When it shrinks or grows, param_end is moved.
  280. ; Format of an entry is as follows:
  281. ;   highest address -> length:word (may be 0)
  282. ;               key to replace:word     (either hi or low byte is zero)
  283. ;               .
  284. ;               .    new key value, "length" bytes long
  285. ;               .
  286. ;   lowest address  -> next entry, or free space.
  287. ; If no arguments are given, keyboard is reset to default condition.
  288. ; Otherwise, first parameter (or first two, if first is zero) defines
  289. ; the key whose value is to be changed, and the following parameters
  290. ; define the key's new, possibly zero-length, value.
  291.  
  292. key:
  293.     ; Is this a reset?
  294.     or    cx, cx
  295.     jz    key_init
  296.     ; Get the first (or first two) parameters
  297.     cld
  298.     dec    si    ; point to first param
  299.     dec    cx    ; Assume it's a fn key, get two params
  300.     dec    cx
  301.     lodsw
  302.     or    al, al    ; Is it a function key?
  303.     jz    key_fnkey
  304.         ; It's not a function key- put second param back
  305.         inc    cx
  306.         dec    si
  307. key_fnkey:
  308.     ; Key to redefine now in AX.  If it's already redefined,
  309.     ; lookup will set Z, point SI to redef string, set CX to its length.
  310.     push    di
  311.     push    es
  312.     push    cx
  313.     push    si
  314.  
  315.     std            ; moving up, must move from top down
  316.     push    ds
  317.     pop    es        ; string move must have ES=DS
  318.     call    lookup        ; rets Z if redefined...
  319.     jnz    key_newkey
  320.     ; It's already defined.  Erase its old definition- i.e., move
  321.     ; region param_end+1..SI-1 upwards CX+4 bytes, add CX+4 to param_end.
  322.     add    cx, 4
  323.     mov    bp, param_end    ; save old value in bp...
  324.     add    param_end, cx
  325.     dec    si        ; start at (SI-1)
  326.     mov    di, si
  327.     add    di, cx        ; move to (start + CX+4)
  328.     mov    cx, si
  329.     sub    cx, bp        ; length of region old_param_end+1..start
  330.     rep    movsb
  331. key_newkey:
  332.     ; Key not redefined.  See if there's enough room to redefine it.
  333.     pop    si        ; get back pointer to redef string
  334.     pop    cx        ; get back number of bytes in redef string
  335.     mov    di, param_end    ; hi byte of new redef record, hi byte of len
  336.     sub    di, 4        ; hi byte of new data field
  337.     mov    bx, di
  338.     sub    bx, cx        ; hi byte of remaining buffer space
  339.     sub    bx, 16        ; better be at least 16 bytes room
  340.     cmp    bx, param_buffer
  341.     jb    key_popem    ; nope- forget it.
  342.     ; Nothing in the way now!
  343.     mov    [di+3], cx    ; save length field
  344.     mov    [di+1], ax    ; save name field
  345.     jcxz    key_nullstring
  346. key_saveloop:            ; save data field
  347.     movsb
  348.     add    si, 2        ; input string ascending, output descending
  349.     loop    key_saveloop
  350. key_nullstring:
  351.     mov    param_end, di    ; save adr of new hi byte of free area
  352. key_popem:
  353.     pop    es
  354.     pop    di
  355.  
  356. key_exit:
  357.     cld
  358.     ret
  359.  
  360. key_init:
  361.     ; Build the default redefinition table:
  362.     ;    control-printscreen -> control-P
  363.     push    es
  364.     push    ds
  365.     pop    es
  366.     std
  367.     mov    di, redef_end
  368.     mov    ax, 1
  369.     stosw
  370.     mov    ax, 7200h    ; control-printscreen
  371.     stosw
  372.     mov    al, 16        ; control P
  373.     stosb
  374.     mov    param_end, di    ; save new bottom of redef table
  375.     pop    es
  376.     jmp    key_exit
  377.  
  378. ;---- Delete/Insert Lines -------------------------------
  379. ; AL is number of lines to delete/insert.
  380. ; Preserves DX, DI; does not move cursor.
  381.  
  382. d_l:    ; Delete lines.
  383.     mov    ah, 6            ; BIOS: scroll up
  384.     jmp    short il_open
  385.  
  386. il:    ; Insert lines.
  387.     mov    ah, 7            ; BIOS: scroll down
  388.  
  389. il_open:
  390.     ; Whether inserting or deleting, limit him to (max_y - cur_y) lines;
  391.     ; if above that, we're just clearing; set AL=0 so BIOS doesn't burp.
  392.     mov    bh, max_y
  393.     sub    bh, cur_y
  394.     cmp    al, bh
  395.     jbe    il_ok            ; DRK 9/4...
  396.         mov    al, 0        ; he tried to move too far
  397. il_ok:
  398.     push    ax
  399.     call    get_blank_attrib
  400.     mov    bh, ah            ; color to use on new blank areas
  401.     pop    ax            ; AL is number of lines to scroll.
  402.  
  403.     mov    cl, 0            ; upper-left-x of data to scroll
  404.     mov    ch, cur_y        ; upper-left-y of data to scroll
  405.     push    dx
  406.     mov    dl, max_x        ; lower-rite-x
  407.     mov    dh, max_y        ; lower-rite-y (zero based)
  408.     int    10h            ; call BIOS to scroll a rectangle.
  409.     pop    dx
  410.     ret                ; done.
  411.  
  412. ;-- Insert / Delete Characters ----------------------------
  413. ; AL is number of characters to insert or delete.
  414. ; Preserves DX, DI; does not move cursor.
  415.  
  416. ic:    mov    ch, 1            ; 1 => swap dest & source below
  417.     jmp    short dc_ch
  418.  
  419. dc:    mov    ch, 0
  420.  
  421. dc_ch:
  422.     call    in_g_mode
  423.     jnc    dc_ret            ; | if in graphics mode, ignore.
  424.  
  425.     ; AL = number of chars to ins or del (guarenteed nonzero).
  426.     ; Limit him to # of chars left on line.
  427.     cmp    al, dl
  428.     jbe    dc_cok
  429.         mov    al, dl
  430. dc_cok:
  431.     push    di            ; DI is current address of cursor
  432.     xchg    ax, cx            ; CX gets # of chars to ins/del
  433.     mov    bp, cx            ; BP gets # of columns to clear.
  434.  
  435.     ; Set up source = destination + cx*2, count = dx - cx
  436.     mov    ch, 0            ; make it a word
  437.     mov    si, di
  438.     add    si, cx
  439.     add    si, cx
  440.     neg    cl
  441.     add    cl, dl
  442.     mov    ch, 0            ; CX = # of words to transfer
  443.     cld                ; REP increments si & di
  444.  
  445.     ; If this is an insert, then flip transfer around in both ways.
  446.     test    ah, 1
  447.     jz    dc_noswap
  448.         xchg    di, si        ; source <-> dest
  449.         std            ; up <-> down
  450.         mov    ax, cx        ; make move over same range
  451.         dec    ax
  452.         add    ax, ax        ; AX=dist from 1st to last byte.
  453.         add    di, ax        ; Start transfer at high end of block
  454.         add    si, ax        ;  instead of low end.
  455. dc_noswap:
  456.     ; Move those characters.
  457.     push    es
  458.     pop    ds
  459.     rep    movsw
  460.     mov    cx, bp
  461.     ; Figure out what color to make the new blanks.
  462.     call    get_blank_attrib
  463.     mov    al, ' '
  464.     ; Blank out vacated region.
  465.     rep    stosw
  466.  
  467.     ; All done.
  468.     cld                ; restore normal REP state and
  469.     pop    di            ;  cursor address.
  470. dc_ret: ret
  471.  
  472.  
  473. ;---- set / reset mode ---------------------------------------
  474. ; Sets graphics/text mode; also sets/resets "no wrap at eol" mode.
  475. sm:    mov    cl, 0ffh    ; set
  476. sm_rs:
  477.     ; Is it "wrap at eol" ?
  478.     cmp    al, 7
  479.     jnz    sm_notwrap
  480.         mov    wrap_flag, cl    ; true = wrap at EOL
  481.         jmp    short sm_done
  482. sm_notwrap:
  483.     ; Is it "set highest number of screen lines available"?
  484.     cmp    al, 43
  485.     jnz    sm_video
  486.         ; Only valid for the Enhanced Graphics Adaptor on
  487.         ; a monochrome display or an enhanced color display.
  488.         ; Test presence of EGA by calling BIOS fn 12h.10h.
  489.         mov    ah, 12h
  490.         mov    bx, 0ff10h
  491.         int    10h            ; bh=0-1, bl=0-3 if EGA
  492.         test    bx, 0FEFCH
  493.         jnz    sm_done            ; sorry, charlie
  494. ;        mov    port_6845, 3d4h
  495. ;        mov    al, video_mode
  496. ;        and    al, 7
  497. ;        cmp    al, 7            ; monochrome monitor?
  498. ;        jnz    sm_colormon
  499. ;            mov    byte ptr port_6845, low(3b4h)
  500. ;sm_colormon:
  501.         ; 43 line mode only allowed in text modes, for now.
  502.         call    in_g_mode
  503.         jnc    sm_done
  504.  
  505.         mov    ah, 0            ; "Set video mode"
  506.         mov    al, video_mode        ; Re-init current mode
  507.         int    10h
  508.  
  509.         mov    ax,1112h        ; Load 8x8 font
  510.         mov    bl,0            ; (instead of 8x14)
  511.         int    10h
  512.  
  513.         mov    ax, 1200h        ; Load new printscreen
  514.         mov    bl, 20h
  515.         int    10h
  516.  
  517.         mov    ah,1
  518.         mov    cx,0707h        ; (Load cursor scan lines)
  519.         int    10h
  520.         ; | Patch; this gotten by painful observation of
  521.         ; | IBM's professional editor.    I think there's a
  522.         ; | documented bug in Video Bios's "load cursor scan line"
  523.         ; | call; try looking in latter 1985 PC Tech Journal.
  524.         mov    dx, port_6845        ; '6845' command reg
  525.         mov    al, 10
  526.         out    dx, al
  527.         jmp    $+2
  528.         inc    dx
  529.         mov    al, 7
  530.         out    dx, al            ; set cursor start line
  531.         ; Assume that gets us 43 lines.
  532.         mov    max_y, 42
  533.         jmp    short sm_home
  534. sm_video:
  535.     ; It must be a video mode.  Call BIOS.
  536.     mov    ah, 0        ; "set video mode"
  537.     int    10h
  538.     ; Assume that gets us 25 lines.
  539.     mov    max_y, 24
  540. sm_home:
  541.     ; Read the BIOS buffer address/cursor position variables.
  542.     mov    ax, abs40
  543.     push    ds
  544.     mov    ds, ax
  545.     assume    ds:abs40
  546.     ; Find current video mode and screen size.
  547.     mov    ax,word ptr crt_mode    ; al = crt mode; ah = # of columns
  548.     pop    ds
  549.     mov    video_mode, al
  550.     dec    ah            ; ah = max column
  551.     mov    max_x, ah
  552.  
  553.     ; Since cursor may end up in illegal position, it's best to
  554.     ; just go home after switching video modes.
  555.     mov    cur_coords, 0
  556.     call    xy_to_regs
  557. sm_done:
  558.     ret
  559.  
  560. rm:    mov    cl, 0        ; reset
  561.     jmp    sm_rs
  562.  
  563. ;------- Output Character Translation ----------------------
  564. ; A decidedly nonstandard function, possibly useful for editing files
  565. ; intended to be printed by daisywheel printers with strange wheels.
  566. ; (The letter 'y' was chosen to conflict with the VT100 self-test command.)
  567. ; Usage: ESC [ #1;#2 y
  568. ; where #1 is the character to redefine
  569. ;    #2 is the new display value
  570. ; If only ESC [ #1 y is sent, character #1 is reset to its default value.
  571. ; If only ESC [ y is sent, the entire table is reset to the default value.
  572. ; (If only ESC [ #1; y is sent, character #1 is set to zero... sigh.)
  573.  
  574. xoc:    ; Xlate output character
  575.     mov    bx, xlate_tab_ptr
  576.     jcxz    xoc_reset    ; if no parameters, reset table to 1:1
  577.     dec    si        ; point to first parameter
  578.     lodsw            ; first parameter to AL, second to AH
  579.     dec    cx        ; is parameter count 1?
  580.     jnz    xoc_bothparams
  581.         mov    ah, al    ; if only one param, reset that char.
  582. xoc_bothparams:
  583.     add    bl, al
  584.     adc    bh, 0        ; bx points to entry for char AL
  585.     mov    byte ptr [bx], ah    ; change that entry
  586. xoc_done:
  587.     ret
  588.  
  589. xoc_reset:
  590.     ; Fill table with default values- i.e. 0, 1, 2, ... 255.
  591.     xor    ax, ax
  592. xoc_loop:
  593.     mov    byte ptr [bx], al
  594.     inc    bx
  595.     inc    al
  596.     jnz    xoc_loop
  597.     jmp    xoc_done
  598.  
  599. ansi_functions    endp    ; end dummy procedure block
  600.  
  601.  
  602.  
  603. ;-------- Color table -----------------------------------------
  604. ; Used in "set graphics rendition"
  605. colors    equ    22            ; number of colors in table
  606. color_table:
  607.     db    0, 000h,07h        ; all attribs off; normal.
  608.     db    1, 0ffh,08h        ; bold
  609.     db    4, 0f8h,01h        ; underline
  610.     db    5, 0ffh,80h        ; blink
  611.     db    7, 0f8h,70h        ; reverse
  612.     db    8, 088h,00h        ; invisible
  613.  
  614.     db    30,0f8h,00h        ; black foreground
  615.     db    31,0f8h,04h        ; red
  616.     db    32,0f8h,02h        ; green
  617.     db    33,0f8h,06h        ; yellow
  618.     db    34,0f8h,01h        ; blue
  619.     db    35,0f8h,05h        ; magenta
  620.     db    36,0f8h,03h        ; cyan
  621.     db    37,0f8h,07h        ; white
  622.  
  623.     db    40,08fh,00h        ; black background
  624.     db    41,08fh,40h        ; red
  625.     db    42,08fh,20h        ; green
  626.     db    43,08fh,60h        ; yellow
  627.     db    44,08fh,10h        ; blue
  628.     db    45,08fh,50h        ; magenta
  629.     db    46,08fh,30h        ; cyan
  630.     db    47,08fh,70h        ; white
  631.  
  632.  
  633. code    ends
  634.     end                ; of nansi_f.asm
  635.  
  636.     page    66, 132
  637.